from typing import Literal
from pydantic import BaseModel, conlist, conint, confloat

from settings import settings


class Delays(BaseModel):
    sv_rx_delay: conlist(float, min_items=settings.DSP_NUMBER, max_items=settings.DSP_NUMBER)
    sv_tx_delay: conlist(float, min_items=settings.DSP_NUMBER, max_items=settings.DSP_NUMBER)

    class Config:
        validate_assignment = True


class BaseCalibration(BaseModel):
    uplink_sv_rx_base_addr: conint() = 0x83C3_0000
    uplink_link_rx_base_addr: conint() = 0x83C4_0000
    uplink_base_addr: conint() = 0x83C5_0000
    downlink_base_addr: conint() = 0x83C6_0000
    uplink_pilot_base_addr: conint() = 0x83CC_0000
    downlink_pilot_base_addr: conint() = 0x83CD_0000

    delay_1_offset: conint() = 0x20
    delay_2_offset: conint() = 0x22
    delay_3_offset: conint() = 0x24
    delay_4_offset: conint() = 0x26

    max_value: conint() = 0xFFFF_FFFF

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.uplink_sv_rx_base_addr = self.uplink_sv_rx_base_addr
        self.uplink_link_rx_base_addr = self.uplink_link_rx_base_addr
        self.uplink_base_addr = self.uplink_base_addr
        self.downlink_base_addr = self.downlink_base_addr
        self.uplink_pilot_base_addr = self.uplink_pilot_base_addr
        self.downlink_pilot_base_addr = self.downlink_pilot_base_addr

        self.delay_1_offset = self.delay_1_offset
        self.delay_2_offset = self.delay_2_offset
        self.delay_3_offset = self.delay_3_offset
        self.delay_4_offset = self.delay_4_offset

        self.max_value = self.max_value

    class Config:
        validate_assignment = True


class CalibrationCoe(BaseCalibration):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.calibration_coe_configs: dict = {
            'COE_UL_LNK_LNK': {'addr': self.uplink_link_rx_base_addr, 'offset': 0x18, 'loaded_coe-1': '5MHz_191',
                               'loaded_coe-2': '5MHz_191', 'loaded_coe-3': '5MHz', 'loaded_coe-4': '5MHz'},
            'COE_UL_SV_LNK': {'addr': self.uplink_sv_rx_base_addr, 'offset': 0x18, 'loaded_coe-1': '5MHz_191',
                              'loaded_coe-2': '5MHz_191', 'loaded_coe-3': '5MHz', 'loaded_coe-4': '5MHz'},
            'COE_DL_LNK_SV': {'addr': self.downlink_base_addr, 'offset': 0x18, 'loaded_coe-1': '5MHz_191',
                              'loaded_coe-2': '5MHz_191', 'loaded_coe-3': '5MHz', 'loaded_coe-4': '5MHz'},
        }


class MyList(list):
    def __init__(self, *args):
        super(MyList, self).__init__(args)

    def __sub__(self, other):
        return self.__class__(*[item for item in self if item not in other])


class DspConfig(BaseModel):
    c: conlist(float, min_items=settings.DSP_NUMBER, max_items=settings.DSP_NUMBER) = [0.0] * settings.DSP_NUMBER

    def __neg__(self):
        return DspConfig(c=[-n for n in self.c])

    def __floordiv__(self, other):
        DspConfig(c=[n // other for n in self.c])


class DspModesConfig(BaseModel):
    add_mode: bool = False
    inj_dat_from2ch_to_serv3_4: bool = False
    serv1_to_serv1_and_serv2: bool = False
    service_4_on_nb_Ch: bool = False
    service_3_on_nb_Ch: bool = False
    service_4_on_without_add_filter: bool = False
    service_3_on_without_add_filter: bool = False
    ul_on_nb_off_wb: bool = False
    ul_mode_on_add_off_std: bool = False
    ul_sum_1_and_2_channel: bool = False


class DspSubchannelsControl(BaseModel):
    class SubChannel(BaseModel):
        offset_in: confloat(ge=-9.5, le=9.5) = 0.0
        offset_out: confloat(ge=-9.5, le=9.5) = 0.0

    nb_subchannels_control_service: bool = False
    num_of_band: conint(ge=1, le=4) = 1
    channels: conlist(conint(ge=0, le=1_000), min_items=4, max_items=4) = [0, 0, 0, 0]
    subchannels: conlist(SubChannel, min_items=2, max_items=2) = [SubChannel(), SubChannel()]
    offset_nb_bw: confloat(ge=-50.0, le=50.0) = 0.0
    offset_wb_bw: confloat(ge=-50.0, le=50.0) = 0.0


class FSCCalibration(BaseCalibration):
    LINK_RTX_DL_OFFSET_config_values = [7.5, 2.5, -2.5, -7.5]
    PILOT_FREQUENCY_config_values = [-10.45, 0.25, 0xAA, -10.45]

    fsc_calibration_config: dict = {}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fsc_calibration_config: dict = {
            'LINK_UL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.uplink_link_rx_base_addr,
                              'offset': 0x04},
            'LINK_DL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.downlink_base_addr,
                              'offset': 0x48},

            'SERVICE_TX_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.downlink_base_addr,
                                 'offset': 0x04},
            'SERVICE_RX_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.uplink_sv_rx_base_addr,
                                 'offset': 0x04},

            'LINK_RTX_UL_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_link_rx_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'LINK_RTX_DL_OFFSET': {
                'config': DspConfig(c=[self.LINK_RTX_DL_OFFSET_config_values[i] for i in range(settings.DSP_NUMBER)]),
                'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                'addr': self.downlink_base_addr,
                'offset': 0x38,
                'enable_offset': False},

            'SERVICE_TX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.downlink_base_addr,
                                  'offset': 0x28,
                                  'enable_offset': False},

            'SERVICE_RX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.uplink_sv_rx_base_addr,
                                  'offset': 0x08,
                                  'enable_offset': False},

            'LINK_RX_OUT_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_base_addr,
                                   'offset': 0x04,
                                   'enable_offset': False},

            'LINK_TX_OUT_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'UL_PILOT_FREQUENCY': {
                'config': DspConfig(c=[self.PILOT_FREQUENCY_config_values[i] for i in range(settings.DSP_NUMBER)]),
                'addr': self.uplink_pilot_base_addr,
                'offset': 0},

            'DL_PILOT_FREQUENCY': {
                'config': DspConfig(c=[self.PILOT_FREQUENCY_config_values[i] for i in range(settings.DSP_NUMBER)]),
                'addr': self.downlink_pilot_base_addr,
                'offset': 0},
        }


class BaseFSRCalibration(BaseCalibration):
    LINK_RX_OUT_OFFSET = [-7.5, -2.5, 2.5, 7.5]
    PILOT_FREQUENCY = [-10.45, 0.25, 0xAA, -10.45]


class FSRLink1Calibration(BaseFSRCalibration):
    fsr_link_1_calibration_config = {}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fsr_link_1_calibration_config = {
            'LINK_UL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.uplink_link_rx_base_addr,
                              'offset': 0x04},
            'LINK_DL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.downlink_base_addr,
                              'offset': 0x48},

            'SERVICE_TX_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.downlink_base_addr,
                                 'offset': 0x04},
            'SERVICE_RX_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.uplink_sv_rx_base_addr,
                                 'offset': 0x04},

            'LINK_RTX_UL_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_link_rx_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'LINK_RTX_DL_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_base_addr,
                                   'offset': 0x38,
                                   'enable_offset': False},

            'SERVICE_TX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.downlink_base_addr,
                                  'offset': 0x28,
                                  'enable_offset': False},

            'SERVICE_RX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.uplink_sv_rx_base_addr,
                                  'offset': 0x08,
                                  'enable_offset': False},

            'LINK_RX_OUT_OFFSET': {
                'config': DspConfig(c=[self.LINK_RX_OUT_OFFSET[i] for i in range(settings.DSP_NUMBER)]),
                'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                'addr': self.uplink_base_addr,
                'offset': 0x04,
                'enable_offset': False},

            'LINK_TX_OUT_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'UL_PILOT_FREQUENCY': {'config': DspConfig(c=[self.PILOT_FREQUENCY[i] for i in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_pilot_base_addr,
                                   'offset': 0},

            'DL_PILOT_FREQUENCY': {'config': DspConfig(c=[self.PILOT_FREQUENCY[i] for i in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_pilot_base_addr,
                                   'offset': 0},
        }


class FSRLink2Calibration(BaseFSRCalibration):
    fsr_link_2_calibration_config = {}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fsr_link_2_calibration_config = {
            'LINK_UL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.uplink_link_rx_base_addr,
                              'offset': 0x04},
            'LINK_DL_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                              'addr': self.downlink_base_addr,
                              'offset': 0x48},

            'SERVICE_TX_SCALE': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.downlink_base_addr,
                                 'offset': 0x04},
            'SERVICE_RX_SCALE': {'config': DspConfig(c=[1 for _ in range(settings.DSP_NUMBER)]),
                                 'addr': self.uplink_sv_rx_base_addr,
                                 'offset': 0x04},

            'LINK_RTX_UL_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_link_rx_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'LINK_RTX_DL_OFFSET': {'config': DspConfig(c=[self.LINK_RX_OUT_OFFSET[i] for i in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_base_addr,
                                   'offset': 0x38,
                                   'enable_offset': False},

            'SERVICE_TX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.downlink_base_addr,
                                  'offset': 0x28,
                                  'enable_offset': False},

            'SERVICE_RX_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                  'addr': self.uplink_sv_rx_base_addr,
                                  'offset': 0x08,
                                  'enable_offset': False},

            'LINK_RX_OUT_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_base_addr,
                                   'offset': 0x04,
                                   'enable_offset': False},

            'LINK_TX_OUT_OFFSET': {'config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'offset_config': DspConfig(c=[0 for _ in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_base_addr,
                                   'offset': 0x08,
                                   'enable_offset': False},

            'UL_PILOT_FREQUENCY': {'config': DspConfig(c=[self.PILOT_FREQUENCY[i] for i in range(settings.DSP_NUMBER)]),
                                   'addr': self.uplink_pilot_base_addr,
                                   'offset': 0},

            'DL_PILOT_FREQUENCY': {'config': DspConfig(c=[self.PILOT_FREQUENCY[i] for i in range(settings.DSP_NUMBER)]),
                                   'addr': self.downlink_pilot_base_addr,
                                   'offset': 0},
        }
